#include "prot-filer/fragments_filer.h"

namespace prot_filer
{
bool FragmentsAnglesReaderImple::_open(const std::string& name)
{
    file.open(name.c_str(), std::ios::binary | std::ios::in);
    angles_mapping = h.read_mapping(file);
    const unsigned int nres = angles_mapping->get_nres();
    angles_data = new AnglesData(nres, angles_mapping);
    _atoms_in_a_protein = nres * ATOMS_PER_RESIDUE;
    return file;
}

bool FragmentsAnglesReaderImple::read(AnglesData& protein)
{
    checkOpen();
    if (_atoms_in_a_protein != int(ATOMS_PER_RESIDUE * protein.nres))
        throw std::runtime_error("read(AnglesData) received a protein with the wrong number of residues");

    eof = eof || h.is_next_char_readable(file);

    if (!eof)
    {
        CustomReadBuffer buffer(angles_data->get_angles_mapping().get_mapping_size(), file);

        const unsigned int fragment_size = fragments->get_fragment_size();
        const unsigned int nres = angles_data->nres;
        unsigned int i = 0;
        unsigned int fragment_index = 0;
        const unsigned int end = nres - 1;

        buffer.read_var(fragment_index);
        for (unsigned c = 0; c < fragment_size - 1; ++c)
        {
            protein.angles[i] = (*fragments)[fragment_index].angles[c];
            ++i;
        }

        while (i + fragment_size < end)
        {
            buffer.read_var(fragment_index);
            for (unsigned c = 0; c < fragment_size - 1; ++c)
            {
                protein.angles[i] = (*fragments)[fragment_index].angles[c];
                ++i;
            }
            buffer.read(protein.angles[i]);
            ++i;
        }

        for (; i < end; ++i)
        {
            buffer.read(protein.angles[i]);
        }

        eof = file.eof();
        unsigned char temp;
        if (!(file >> temp) || temp != END_OF_DATA)
            std::cerr << "Read error: Read ended without reaching end of structure." << std::endl;
    }
    return eof;
}

bool FragmentsWriter::_open(const std::string& name)
{
    file.open(name.c_str(), std::ios::binary | std::ios::out);
    return file;
}

void FragmentsWriter::write(const unsigned int fragment_size, const FragmentIds& ids, const AnglesData& angles_data)
{
    checkOpen();
    if (first_time)
    {
        h.write_mapping(file, angles_data.get_angles_mapping());
    }

    const unsigned int nres = angles_data.nres;
    unsigned int i = 0;
    unsigned int fragment_index = 0;
    const unsigned int end = nres - 1;

    CustomWriteBuffer buffer(angles_data.get_angles_mapping().get_mapping_size(), file);

    //primer fragmento, sin semilla => size-1
    buffer.write_var(ids[fragment_index]);
    ++fragment_index;
    i += fragment_size - 1;

    while (i + fragment_size < end)
    {
        buffer.write_var(ids[fragment_index]);
        i += fragment_size - 1;
        ++fragment_index;
        buffer.write(angles_data.angles[i]);
        ++i;
    }

    for (; i < end; ++i)
    {
        buffer.write(angles_data.angles[i]);
    }
    buffer.flush_buffer();
    file << END_OF_DATA;
}

void FragmentsWriter::_close()
{
    file.close();
}
}
